#pragma once

#include <AVUIGeneralTransform3D.h>
#include <AVUIMatrix3D.h>

namespace AVUI {

class Point4D;	

/// <summary>Provides a parent class for all three-dimensional transformations, including translation, rotation, and scale transformations. </summary>
class Transform3D : public GeneralTransform3D
{
public:
    DECLARE_ELEMENT(Transform3D, GeneralTransform3D);

#pragma region Public Methods

    /// <summary>Creates a modifiable clone of this <see cref="T:System.Windows.Media.Media3D.Transform3D" />, making deep copies of this object's values. </summary>
    /// <returns>A modifiable clone of the current object. The cloned object's <see cref="P:System.Windows.Freezable.IsFrozen" /> property is false even if the source's <see cref="P:System.Windows.Freezable.IsFrozen" /> property is true.</returns>
    TRefCountedPtr<Transform3D> Clone() { return (Transform3D*) GeneralTransform3D::Clone().get_Ptr(); }

    /// <summary>Creates a modifiable clone of this <see cref="T:System.Windows.Media.Media3D.Transform3D" /> object, making deep copies of this object's current values. Resource references, data bindings, and animations are not copied, but their current values are.</summary>
    /// <returns>A modifiable clone of the current object. The cloned object's <see cref="P:System.Windows.Freezable.IsFrozen" /> property is false even if the source's <see cref="P:System.Windows.Freezable.IsFrozen" /> property is true.</returns>
    TRefCountedPtr<Transform3D> CloneCurrentValue() { return (Transform3D*) GeneralTransform3D::CloneCurrentValue().get_Ptr(); }

    /// <summary> Transforms the specified array of <see cref="T:System.Windows.Media.Media3D.Point4D" /> objects. </summary>
    /// <returns />
    /// <param name="points">Array of Point4D objects to transform.</param>
    void Transform(Point4D* rgPoints, int cPoints) { get_Value().Transform(rgPoints, cPoints); }

    /// <summary> Transforms the specified array of <see cref="T:System.Windows.Media.Media3D.Vector3D" /> objects. </summary>
    /// <returns />
    /// <param name="vectors">Array of Vector3D objects to transform.</param>
    void Transform(Vector3D* rgVectors, int cVectors) { get_Value().Transform(rgVectors, cVectors); }

    /// <summary>Transforms the specified <see cref="T:System.Windows.Media.Media3D.Point3D" />. </summary>
    /// <returns>Transformed Point3D.</returns>
    /// <param name="point">Point3D to transform.</param>
    Point3D Transform(const Point3D& point) { return GeneralTransform3D::Transform(point); }

    /// <summary>Transforms the specified <see cref="T:System.Windows.Media.Media3D.Point4D" />. </summary>
    /// <returns>Transformed Point4D.</returns>
    /// <param name="point">Point4D to transform.</param>
    Point4D Transform(const Point4D& point) { return get_Value().Transform(point); }

    /// <summary>Transforms the specified <see cref="T:System.Windows.Media.Media3D.Vector3D" />. </summary>
    /// <returns>Transformed Vector3D.</returns>
    /// <param name="vector">Vector3D to transform.</param>
    Vector3D Transform(const Vector3D& vector) { return get_Value().Transform(vector); }

    /// <summary> Transforms the specified array of <see cref="T:System.Windows.Media.Media3D.Point3D" /> objects. </summary>
    /// <returns />
    /// <param name="points">Array of Point3D objects to transform.</param>
    void Transform(Point3D* rgPoints, int cPoints) { get_Value().Transform(rgPoints, cPoints); }

    /// <summary>Transforms the specified 3-D bounding box and returns an axis-aligned 3-D bounding box that is exactly large enough to contain it.</summary>
    /// <returns>The smallest axis-aligned 3-D bounding box possible that contains the transformed <paramref name="rect" />.</returns>
    /// <param name="rect">The 3-D bounding box to transform.</param>
    virtual Rect3D TransformBounds(const Rect3D& rect) AVUI_OVERRIDE;

    /// <summary>Attempts to transform the specified 3-D point and returns a value that indicates whether the transformation was successful.</summary>
    /// <returns>true if <paramref name="inPoint" /> was transformed; otherwise, false.</returns>
    /// <param name="inPoint">The 3-D point to transform.</param>
    /// <param name="result">The result of transforming <paramref name="inPoint" />.</param>
    virtual bool TryTransform(const Point3D& inPoint, Point3D* pResult) AVUI_OVERRIDE;

#pragma endregion Public Methods

#pragma region Public Properties

    /// <summary>Gets the identity transformation. </summary>
    /// <returns>Identity transformation.</returns>
    static Transform3D* get_Identity();

    /// <summary>Gets the inverse transformation of this object, if possible.</summary>
    /// <returns>An inverse of this instance, if possible; otherwise, null.</returns>
    virtual TRefCountedPtr<GeneralTransform3D> get_Inverse();

    /// <summary>Gets a value that specifies whether the matrix is affine. </summary>
    /// <returns>true if the matrix is affine; otherwise, false.</returns>
    virtual bool get_IsAffine() = 0;
 
    /// <summary>Gets the <see cref="T:System.Windows.Media.Media3D.Matrix3D" /> that represents the value of the current transformation. </summary>
    /// <returns>Matrix3D that represents the value of the current transformation.</returns>
    virtual Matrix3D get_Value() = 0;

#pragma endregion Public Properties

public:

#pragma region Internal Methods

    virtual void Append(Matrix3D* pMatrix) = 0;
 
#pragma endregion Internal Methods

#pragma region Internal Properties

    virtual TRefCountedPtr<Transform3D> get_AffineTransform() AVUI_OVERRIDE { return this; }

#pragma endregion Internal Properties

#pragma region Private Statics

static TRefCountedPtr<Transform3D> s_identity;

#pragma endregion Private Statics

};


}; // namespace AVUI
